Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(api): Rotate the calibrated module offset if the module was physically moved and rotated. #13441

Merged
merged 11 commits into from
Oct 4, 2023

Conversation

vegano1
Copy link
Contributor

@vegano1 vegano1 commented Aug 31, 2023

Overview

When a module is calibrated, the generated module offset vector is valid for the current location the module is in. However, if the module is physically moved and rotated across the deck then the original calibrated offset vector is no longer valid. So we need to apply a rotation of 180 degrees to the calibrated module offset vector if the module was ever moved and rotated.

Test Plan

  • Make sure we can still perform a module calibration on all supported modules (temp, heater-shaker, thermocycler)
  • Make sure we are correctly saving/loading the calibrated module offset data
  • Make sure we now return the location data along with the vector offset when executing the CalibrateModule PE command over HTTP.
  • Make sure this does not make well positions and labware grip points less accurate
  • Make sure that the module calibration offset is rotated when the module is physically moved across the deck. The module calibration offset tends to be small <1mm, let's manually edit the stored calibration file in disk to get an exaggerated offset that is easy to visually see a change in.

Changelog

  • Added new ModuleOffsetData type to contain ModuleOffsetVector and DeckSlotLocation data.
  • The CalibrateModuleResult PE command now returns DeckSlotLocation in addition to moduleOffset to be used in ModuleStore.
  • The ModuleStore now uses ModuleOffsetData instead of ModuleOffsetVector since we want to store both the offset and the deck slot location.
  • The get_module_calibration_offset function now rotates the calibrated module offset by 180 degrees if the module was physically moved and rotated to a qualifying deck slot different from the original calibrated location.
  • Make the slot member in the ModuleCalibrationOffset class into a required field since you won't have an offset without performing a calibration.
  • Refactor module calibration loading mechanism so we don't need to pass in a slot arg as this is loaded from disk and will always be present.
  • Loading module calibration now returns Optional[ModuleCalibrationOffset] instead of a default object, as some modules just haven't been calibrated yet and we don't want to assume the slot they were calibrated in.

Review requests

  • I'm a bit iffy on the implementation for the _needs_rotation function as this is a fixed set of locations we use to determine if a rotation is needed or not, so it feels rather brittle. I would love some feedback on this, maybe there's a better way of doing this.

Risk assessment

  • Low, module calibration has not been exposed yet.

@vegano1 vegano1 requested review from a team as code owners August 31, 2023 20:07
@vegano1 vegano1 requested review from sanni-t and sfoster1 August 31, 2023 20:07
@codecov
Copy link

codecov bot commented Aug 31, 2023

Codecov Report

Merging #13441 (ba2bed8) into chore_release-7.0.1 (1879b24) will increase coverage by 0.04%.
Report is 9 commits behind head on chore_release-7.0.1.
The diff coverage is n/a.

Additional details and impacted files

Impacted file tree graph

@@                   Coverage Diff                   @@
##           chore_release-7.0.1   #13441      +/-   ##
=======================================================
+ Coverage                71.27%   71.32%   +0.04%     
=======================================================
  Files                     2427     1588     -839     
  Lines                    68280    52777   -15503     
  Branches                  7998     3443    -4555     
=======================================================
- Hits                     48669    37643   -11026     
+ Misses                   17731    14599    -3132     
+ Partials                  1880      535    -1345     
Flag Coverage Δ
g-code-testing 96.44% <ø> (ø)
notify-server 89.13% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files Coverage Δ
...i/src/opentrons/hardware_control/module_control.py 72.64% <ø> (ø)
api/src/opentrons/hardware_control/ot3api.py 79.59% <ø> (ø)
.../protocol_engine/resources/module_data_provider.py 100.00% <ø> (ø)
...pi/src/opentrons/protocol_engine/state/geometry.py 100.00% <ø> (ø)
api/src/opentrons/protocol_engine/state/modules.py 91.48% <ø> (ø)
api/src/opentrons/protocol_engine/state/state.py 100.00% <ø> (ø)
api/src/opentrons/protocol_engine/types.py 97.56% <ø> (ø)

... and 839 files with indirect coverage changes

Copy link
Contributor

@SyntaxColoring SyntaxColoring left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

api/src/opentrons/protocol_engine/types.py Outdated Show resolved Hide resolved
Comment on lines 116 to 122
A = (
DeckSlotName.SLOT_D1,
DeckSlotName.SLOT_C1,
DeckSlotName.SLOT_B1,
DeckSlotName.SLOT_A1,
)
B = (DeckSlotName.SLOT_D3, DeckSlotName.SLOT_C3, DeckSlotName.SLOT_B3)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we do stick with this basic idea of implementing _needs_rotation() with a fixed set of locations, can we:

  1. Change A and B to COL_1 and COL_3? "A" and "B" are confusing to me because they look like they're referring to row A and row B.
  2. Add DeckSlotName.SLOT_A3, where the fixed trash currently is? I don't want us to forget it when the trash is made movable, and I think it should be harmless to add it now.

api/src/opentrons/protocol_engine/state/modules.py Outdated Show resolved Hide resolved
Copy link
Member

@sfoster1 sfoster1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use the slot transform for this? That would simplify a lot of the logic. The explicit "which slots need rotation" considerations are baked into the module definitions (though they may need added entries for flex-style names).

The slot transforms in the module definitions are 3d affine transforms in encoded matrix form; you can either use them as-is by augmenting the calibration offset to 1x4 with a 0 to get only the linear-transform-part or deaugment the affine transforms back to 3d linear transforms and multiply as normal.

api/src/opentrons/protocol_engine/state/modules.py Outdated Show resolved Hide resolved
api/src/opentrons/protocol_engine/state/modules.py Outdated Show resolved Hide resolved
@sanni-t
Copy link
Member

sanni-t commented Sep 27, 2023

Can we use the slot transform for this? That would simplify a lot of the logic. The explicit "which slots need rotation" considerations are baked into the module definitions (though they may need added entries for flex-style names).

The slot transforms in the module definitions are 3d affine transforms in encoded matrix form; you can either use them as-is by augmenting the calibration offset to 1x4 with a 0 to get only the linear-transform-part or deaugment the affine transforms back to 3d linear transforms and multiply as normal.

Discussed in person with @vegano1 and @sfoster1 : we can't use slot transforms for rotating the calibration offset since that's not what the slot transforms are used as. The slot transforms are entities that will convert the default labwareOffsetVector to one appropriate for a particular slot on a particular machine. It will include rotational components only if the default vector needs to be rotated, which is not true of all modules on the OT2 and not true of any modules on the Flex since the module caddies take care of it for the modules that can be placed in multiple locations (temperature & H/S modules).

So the decision is to apply a separate rotation to just the calibration offset if the saved calibration was done on a slot in a different column than the current location. Then this rotated calibration offset will be added to the nominal, slot transformed module offset to get the final, calibrated offset vector for a labware on the module.

@sfoster1 sfoster1 requested a review from a team as a code owner September 27, 2023 21:00
@sfoster1 sfoster1 requested review from jerader and removed request for a team September 27, 2023 21:00
@sfoster1 sfoster1 changed the base branch from chore_release-7.0.0 to chore_release-7.0.1 September 27, 2023 21:24
remove the redundant modules.get_module_offset since the geometries view now handles a lot of that functionality
Copy link
Member

@sfoster1 sfoster1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good once we get some tests for the rotation process and logic in there!

api/src/opentrons/protocol_engine/state/geometry.py Outdated Show resolved Hide resolved
api/src/opentrons/protocol_engine/state/geometry.py Outdated Show resolved Hide resolved
Copy link
Member

@sanni-t sanni-t left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!
As @sfoster1 mentioned, we should add a test that tests the rotation of the offsets.

api/src/opentrons/hardware_control/ot3api.py Show resolved Hide resolved
api/src/opentrons/protocol_engine/state/geometry.py Outdated Show resolved Hide resolved
api/src/opentrons/protocol_engine/state/modules.py Outdated Show resolved Hide resolved
@vegano1 vegano1 merged commit af7c4d4 into chore_release-7.0.1 Oct 4, 2023
@vegano1 vegano1 deleted the RCORE-820_module_offset_rotation branch October 4, 2023 20:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants